package com.ruicar.afs.cloud.bizcommon.algorithm.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.ruicar.afs.cloud.bizcommon.algorithm.entity.AfsCalInputInfo;
import com.ruicar.afs.cloud.bizcommon.algorithm.enums.CalculateType;
import com.ruicar.afs.cloud.bizcommon.algorithm.feign.*;
import com.ruicar.afs.cloud.bizcommon.algorithm.service.AfsAlgorithmService;
import com.ruicar.afs.cloud.bizcommon.business.bean.AfsRepaymentInfo;
import com.ruicar.afs.cloud.bizcommon.business.dto.CalculatorDTO;
import com.ruicar.afs.cloud.bizcommon.business.entity.FinRentAdjustDetails;
import com.ruicar.afs.cloud.common.core.constant.SecurityConstants;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import com.ruicar.afs.cloud.parameter.commom.enums.WhetherEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yaorui.zhang
 * @version 1.0
 * @Description 算法接口实现类
 * @date create on 2020年6月2日11:09:22
 * @since 1.0
 */
@Slf4j
@Service
@AllArgsConstructor
public class AfsAlgorithmServiceImpl implements AfsAlgorithmService {

    private AmortizationMonthPlanFeign amortizationMonthPlanFeign;
    private CommissionPlanFeign commissionPlanFeign;
    private DiscountFeign discountFeign;
    private IncomeplanFeign incomeplanFeign;
    private RepaymentPlanFeign repaymentPlanFeign;
    private ToolsFeign toolsFeign;

    /**
     * 获取请求头
     *
     * @return
     */
    public Map makeHeader() {
        Map headers = new HashMap<>();
        headers.put(SecurityConstants.AFS_CLEAR, SecurityConstants.AFS_CLEAR);//删除jar包自带的头
        headers.put("Content-Type", "application/json");
        return headers;
    }

    /**
     * 合并期数和金额
     *
     * @param list
     * @return
     * @author sijun.yu
     */
    public void mergedRentAndPeroid(CalculatorDTO condition, List<FinRentAdjustDetails> list) {

        Assert.isTrue(list!=null && list.size()>0,"租金调整列表不能为空");
        if (list != null && list.size() > 0) {
            String peroids = list.stream().map(x -> String.valueOf(x.getPeriod())).collect(Collectors.joining(","));
            condition.setPeroids(peroids);
            String money = list.stream().map(x -> x.getRent().toString()).collect(Collectors.joining(","));
            condition.setMoney(money);
        }
    }

    /**
     * 调用计算器接口，并返回对应还款计划表
     *
     * @param condition
     * @return
     * @author sijun.yu
     */
    public JSONObject calculatePaymentpPlan(CalculatorDTO condition) {

        log.info("还款计划算法输入参数：" + (JSONObject)JSONObject.toJSON(condition));
        JSONObject resultJson = null;
        Map headers = this.makeHeader();
        AfsCalInputInfo dto = new AfsCalInputInfo();
        dto.setLoanAmount(condition.getLoanAmt());
        dto.setTerm(condition.getLoanTerm());
        dto.setRate(condition.getCustRate());
        String activeDate = condition.getActiveDate();
        if(StringUtils.isEmpty(activeDate)){
            activeDate = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        }
        dto.setActiveDate(activeDate);

        // 等额本金
        if (CalculateType.equalprincipal.getValue().equals(condition.getAlgorithmType())) {
            resultJson = repaymentPlanFeign.equalprincipal(dto, headers);
            log.info("equalprincipal返回还款计划报文：" + resultJson);
        }
        // 分段贷
        else if (CalculateType.ballonloan.getValue().equals(condition.getAlgorithmType())) {
            dto.setBallonLoanType(Integer.valueOf(condition.getBallonLoanType()));
            // 非尾款
            if (WhetherEnum.No.getIndex().equals(condition.getIsTail())) {
                dto.setPeroids(condition.getPeroids());
                dto.setMoney(condition.getMoney());
            } else {
                dto.setPeroids(condition.getLoanTerm().toString());
                dto.setMoney(condition.getTailPayAmt().toString());
            }
            resultJson = repaymentPlanFeign.ballonloan(dto, headers);
            log.info("ballonloan返回还款计划报文：" + resultJson);
        }
        // 等比累进
        else if (CalculateType.equalratioret.getValue().equals(condition.getAlgorithmType())) {
            Integer step = condition.getLoanTerm()/condition.getStep();
            Assert.isTrue(condition.getLoanTerm()%condition.getStep()==0,"请输入正确的期数，必须是"+condition.getStep()+"的倍数");
            dto.setStep(step);
            dto.setStepPercent(condition.getStepPercent());
            resultJson = repaymentPlanFeign.equalratioret(dto, headers);
            log.info("equalratioret返回还款计划报文" + resultJson);
        }
        // 等额累进
        else if (CalculateType.equalquota.getValue().equals(condition.getAlgorithmType())) {
            Integer step = condition.getLoanTerm()/condition.getStep();
            Assert.isTrue(condition.getLoanTerm()%condition.getStep()==0,"请输入正确的期数，必须是"+condition.getStep()+"的倍数");
            dto.setStep(step);
            dto.setQuota(condition.getQuota());
            resultJson = repaymentPlanFeign.equalquota(dto, headers);
            log.info("equalquota返回还款计划报文" + resultJson);
        }
        // 灵活贴息
        else if (CalculateType.flexiblediscount.getValue().equals(condition.getAlgorithmType())) {
            dto.setRate(condition.getSettleRate());
            dto.setDiscount(condition.getDiscountAmt());
            resultJson = repaymentPlanFeign.flexiblediscount(dto, headers);
            log.info("flexiblediscount返回还款计划表" + resultJson);
        }
        // 任意贷
        else if (CalculateType.arbitraryloan.getValue().equals(condition.getAlgorithmType())) {
            // 合并租金和期数
            this.mergedRentAndPeroid(condition, condition.getRentList());
            dto.setPeroids(condition.getPeroids());
            dto.setMoney(condition.getMoney());
            resultJson = repaymentPlanFeign.arbitraryloan(dto, headers);
            log.info("arbitraryloan返回还款计划表" + resultJson);
        }
        // 结构化还款
        else if (CalculateType.structuredloan.getValue().equals(condition.getAlgorithmType())) {
            dto.setStructuredMonth(condition.getStructuredMonth());
            dto.setStructuredType(condition.getStructuredType());
            dto.setStructuredMoney(condition.getStructuredMoney());
            resultJson = repaymentPlanFeign.structuredloan(dto, headers);
            log.info("structuredloan返回还款计划表" + resultJson);
        }
        // 默认等额本息
        else {
            resultJson = repaymentPlanFeign.equalrental(dto, headers);
            log.info("equalrental返回还款计划报文：" + resultJson);
        }
        // 判断是否报错
        Assert.isTrue(1 == resultJson.getInteger("success"), resultJson.getString("message"));
        return resultJson;
    }

    /**
     * 计算贴息金额
     *
     * @param condition
     * @return
     * @author sijun.yu
     */
    public JSONObject calculateDiscount(CalculatorDTO condition) {

        JSONObject resultJson = null;
        Map headers = this.makeHeader();
        AfsCalInputInfo dto = new AfsCalInputInfo();
        dto.setLoanAmount(condition.getLoanAmt());
        dto.setTerm(condition.getLoanTerm());
        dto.setRate(condition.getCustRate());
        String activeDate = condition.getActiveDate();
        if(StringUtils.isEmpty(activeDate)){
            activeDate = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        }
        dto.setActiveDate(activeDate);
        dto.setActualRate(condition.getSettleRate());

        // 等额本金
        if (CalculateType.equalprincipal.getValue().equals(condition.getAlgorithmType())) {
            resultJson = discountFeign.equalprincipal(dto, headers);
            log.info("equalprincipal返回贴息金额报文：" + resultJson);
        }
        // 分段贷
        else if (CalculateType.ballonloan.getValue().equals(condition.getAlgorithmType())) {
            dto.setBallonLoanType(Integer.valueOf(condition.getBallonLoanType()));
            // 非尾款
            if (WhetherEnum.No.getIndex().equals(condition.getIsTail())) {
                dto.setPeroids(condition.getPeroids());
                dto.setMoney(condition.getMoney());
            } else {
                dto.setPeroids(condition.getLoanTerm().toString());
                dto.setMoney(condition.getTailPayAmt().toString());
            }
            resultJson = discountFeign.ballonloan(dto, headers);
            log.info("ballonloan返回贴息金额报文：" + resultJson);
        }
        // 等比累进
        else if (CalculateType.equalratioret.getValue().equals(condition.getAlgorithmType())) {
            Integer step = condition.getLoanTerm()/condition.getStep();
            Assert.isTrue(condition.getLoanTerm()%condition.getStep()==0,"请输入正确的期数，必须是"+condition.getStep()+"的倍数");
            dto.setStep(step);
            dto.setStepPercent(condition.getStepPercent());
            resultJson = discountFeign.equalratioret(dto, headers);
            log.info("equalratioret返回贴息金额报文：" + resultJson);
        }
        // 等额累进
        else if (CalculateType.equalquota.getValue().equals(condition.getAlgorithmType())) {
            Integer step = condition.getLoanTerm()/condition.getStep();
            Assert.isTrue(condition.getLoanTerm()%condition.getStep()==0,"请输入正确的期数，必须是"+condition.getStep()+"的倍数");
            dto.setStep(step);
            dto.setQuota(condition.getQuota());
            resultJson = discountFeign.equalquota(dto, headers);
            log.info("equalquota返回贴息金额报文：" + resultJson);
        }
        // 任意贷
        else if (CalculateType.arbitraryloan.getValue().equals(condition.getAlgorithmType())) {
            // 合并租金和期数
            this.mergedRentAndPeroid(condition, condition.getRentList());
            dto.setPeroids(condition.getPeroids());
            dto.setMoney(condition.getMoney());
            resultJson = discountFeign.arbitraryloan(dto, headers);
            log.info("arbitraryloan返回贴息金额报文：" + resultJson);
        }
        // 结构化还款
        else if (CalculateType.structuredloan.getValue().equals(condition.getAlgorithmType())) {
            dto.setStructuredMonth(condition.getStructuredMonth());
            dto.setStructuredMoney(condition.getStructuredMoney());
            dto.setStructuredType(condition.getStructuredType());
            resultJson = discountFeign.structuredloan(dto, headers);
            log.info("structuredloan返回贴息金额报文：" + resultJson);
        }
        // 默认等额本息
        else {
            resultJson = discountFeign.equalrental(dto, headers);
            log.info("equalrental返回贴息金额报文：" + resultJson);
        }
        // 判断是否报错
        Assert.isTrue(1 == resultJson.getInteger("success"), resultJson.getString("message"));
        return resultJson;
    }

    /**
     * 通过贴息金额获取客户利率
     *
     * @param condition
     * @return
     * @author sijun.yu
     */
    public IResponse getCustomerRate(CalculatorDTO condition) {

        Map headers = this.makeHeader();
        AfsCalInputInfo dto = new AfsCalInputInfo();
        dto.setLoanAmount(condition.getLoanAmt());
        dto.setTerm(condition.getLoanTerm());
        dto.setRate(condition.getSettleRate());
        dto.setDiscount(condition.getDiscountAmt());
        log.info("获取客户利率方法输入参数：" + (JSONObject)JSONObject.toJSON(dto));
        JSONObject result = toolsFeign.getcustomerrateceiling(dto, headers);
        if (result.containsKey("success") && 1 == result.getInteger("success")) {
            BigDecimal custRate = result.getBigDecimal("data");
            return IResponse.success(custRate);
        } else {
            String message = result.getString("message");
            String code = result.getString("code");
            return IResponse.fail("code:" + code + ",message:" + message);
        }
    }

    /**
     * 佣金计划
     *
     * @param info
     * @param algorithmType
     * @return
     */
    public IResponse<ArrayList<AfsRepaymentInfo>> getcommissionplan(AfsCalInputInfo info, String algorithmType) {
        //请求头
        Map headers = makeHeader();
        //接口返回结果
        JSONObject result = new JSONObject();
        //根据算法方式调用接口
        if (CalculateType.equalrental.getValue().equals(algorithmType)) {
            result = commissionPlanFeign.equalrental(info, headers);
        } else if (CalculateType.equalprincipal.getValue().equals(algorithmType)) {
            result = commissionPlanFeign.equalprincipal(info, headers);
        } else if (CalculateType.ballonloan.getValue().equals(algorithmType)) {
            result = commissionPlanFeign.ballonloan(info, headers);
        } else if (CalculateType.structuredloan.getValue().equals(algorithmType)) {
            result = commissionPlanFeign.structuredloan(info, headers);
        } else if (CalculateType.flexiblediscount.getValue().equals(algorithmType)) {
            result = commissionPlanFeign.flexiblediscount(info, headers);
        } else if (CalculateType.equalquota.getValue().equals(algorithmType)) {
            result = commissionPlanFeign.equalquota(info, headers);
        } else if (CalculateType.arbitraryloan.getValue().equals(algorithmType)) {
            result = commissionPlanFeign.arbitraryloan(info, headers);
        } else if (CalculateType.equalratioret.getValue().equals(algorithmType)) {
            result = commissionPlanFeign.equalratioret(info, headers);
        } else {
            return IResponse.fail("请确定调用的算法接口！");
        }
        //结果解析
        if (result.containsKey("success") && 1 == Integer.parseInt(String.valueOf(result.get("success")))) {//只有成功时，方可返回正确的值
            ArrayList<AfsRepaymentInfo> list = (ArrayList<AfsRepaymentInfo>) result.get("data");
            return IResponse.success(list);
        } else {
            String message = (String) result.get("message");
            String code = (String) result.get("code");
            return IResponse.fail("code:" + code + ",message:" + message);
        }
    }

    /**
     * 摊销计划
     *
     * @param condition
     * @return
     * @author sijun.yu
     */
    public JSONObject getAmortizationMonthPlan(CalculatorDTO condition) {

        log.info("摊销计划算法输入参数：" + (JSONObject)JSONObject.toJSON(condition));
        JSONObject resultJson = null;
        Map headers = makeHeader();
        AfsCalInputInfo dto = new AfsCalInputInfo();
        dto.setLoanAmount(condition.getLoanAmt());
        dto.setTerm(condition.getLoanTerm());
        dto.setRate(condition.getCustRate());
        String activeDate = condition.getActiveDate();
        if(StringUtils.isEmpty(activeDate)){
            activeDate = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        }
        dto.setActiveDate(activeDate);
        dto.setActualRate(condition.getSettleRate());
        String algorithmType = condition.getAlgorithmType();
        // 等额本息
        if (CalculateType.equalrental.getValue().equals(algorithmType)) {
            resultJson = amortizationMonthPlanFeign.equalrental(dto, headers);
            log.info("equalrental返回摊销计划报文：" + resultJson);
        }
        // 等额本金
        else if (CalculateType.equalprincipal.getValue().equals(algorithmType)) {
            resultJson = amortizationMonthPlanFeign.equalprincipal(dto, headers);
            log.info("equalprincipal返回摊销计划报文：" + resultJson);
        }
        // 分段贷
        else if (CalculateType.ballonloan.getValue().equals(algorithmType)) {
            dto.setBallonLoanType(Integer.valueOf(condition.getBallonLoanType()));
            // 非尾款
            if (WhetherEnum.No.getIndex().equals(condition.getIsTail())) {
                dto.setPeroids(condition.getPeroids());
                dto.setMoney(condition.getMoney());
            } else {
                dto.setPeroids(condition.getLoanTerm().toString());
                dto.setMoney(condition.getTailPayAmt().toString());
            }
            resultJson = amortizationMonthPlanFeign.ballonloan(dto, headers);
            log.info("ballonloan返回摊销计划报文：" + resultJson);
        }
        // 结构化还款
        else if (CalculateType.structuredloan.getValue().equals(algorithmType)) {
            dto.setStructuredMonth(condition.getStructuredMonth());
            dto.setStructuredMoney(condition.getStructuredMoney());
            dto.setStructuredType(condition.getStructuredType());
            resultJson = amortizationMonthPlanFeign.structuredloan(dto, headers);
            log.info("structuredloan返回摊销计划报文：" + resultJson);
        }
        // 灵活贴息
        else if (CalculateType.flexiblediscount.getValue().equals(algorithmType)) {
            dto.setRate(condition.getSettleRate());
            dto.setDiscount(condition.getDiscountAmt());
            resultJson = amortizationMonthPlanFeign.flexiblediscount(dto, headers);
            log.info("flexiblediscount返回摊销计划报文：" + resultJson);
        }
        // 等额累进
        else if (CalculateType.equalquota.getValue().equals(algorithmType)) {
            Integer step = condition.getLoanTerm()/condition.getStep();
            Assert.isTrue(condition.getLoanTerm()%condition.getStep()==0,"请输入正确的期数，必须是"+condition.getStep()+"的倍数");
            dto.setStep(step);
            dto.setQuota(condition.getQuota());
            resultJson = amortizationMonthPlanFeign.equalquota(dto, headers);
            log.info("equalquota返回摊销计划报文：" + resultJson);
        }
        // 等比累进
        else if (CalculateType.equalratioret.getValue().equals(algorithmType)) {
            Integer step = condition.getLoanTerm()/condition.getStep();
            Assert.isTrue(condition.getLoanTerm()%condition.getStep()==0,"请输入正确的期数，必须是"+condition.getStep()+"的倍数");
            dto.setStep(step);
            dto.setStepPercent(condition.getStepPercent());
            resultJson = amortizationMonthPlanFeign.equalratioret(dto, headers);
            log.info("equalratioret返回摊销计划报文：" + resultJson);
        }
        // 任意贷
        else if (CalculateType.arbitraryloan.getValue().equals(algorithmType)) {
            // 合并租金和期数
            this.mergedRentAndPeroid(condition, condition.getRentList());
            dto.setPeroids(condition.getPeroids());
            dto.setMoney(condition.getMoney());
            resultJson = amortizationMonthPlanFeign.arbitraryloan(dto, headers);
            log.info("arbitraryloan返回摊销计划报文：" + resultJson);
        }
        Assert.isTrue(1 == resultJson.getInteger("success"), resultJson.getString("message"));
        return resultJson;
    }

    /**
     * 收入计划
     *
     * @author sijun.yu
     * @param condition
     * @return
     */
    public JSONObject getIncomePlan(CalculatorDTO condition) {

        log.info("收入计划算法输入参数：" + (JSONObject)JSONObject.toJSON(condition));
        JSONObject resultJson = null;
        Map headers = makeHeader();
        AfsCalInputInfo dto = new AfsCalInputInfo();
        dto.setLoanAmount(condition.getLoanAmt());
        dto.setTerm(condition.getLoanTerm());
        dto.setRate(condition.getCustRate());
        String activeDate = condition.getActiveDate();
        if(StringUtils.isEmpty(activeDate)){
            activeDate = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        }
        dto.setActiveDate(activeDate);
        dto.setActualRate(condition.getSettleRate());
        String algorithmType = condition.getAlgorithmType();
        // 等本息还款
        if (CalculateType.equalrental.getValue().equals(algorithmType)) {
            resultJson = incomeplanFeign.equalrental(dto, headers);
            log.info("equalrental返回收入计划报文：" + resultJson);
        }
        // 等本金还款
        else if (CalculateType.equalprincipal.getValue().equals(algorithmType)) {
            resultJson = incomeplanFeign.equalprincipal(dto, headers);
            log.info("equalprincipal返回收入计划报文：" + resultJson);
        }
        // 分段贷还款
        else if (CalculateType.ballonloan.getValue().equals(algorithmType)) {
            dto.setBallonLoanType(Integer.valueOf(condition.getBallonLoanType()));
            // 非尾款
            if (WhetherEnum.No.getIndex().equals(condition.getIsTail())) {
                dto.setPeroids(condition.getPeroids());
                dto.setMoney(condition.getMoney());
            } else {
                dto.setPeroids(condition.getLoanTerm().toString());
                dto.setMoney(condition.getTailPayAmt().toString());
            }
            resultJson = incomeplanFeign.ballonloan(dto, headers);
            log.info("ballonloan返回收入计划报文：" + resultJson);
        }
        // 结构化还款
        else if (CalculateType.structuredloan.getValue().equals(algorithmType)) {
            dto.setStructuredMonth(condition.getStructuredMonth());
            dto.setStructuredMoney(condition.getStructuredMoney());
            dto.setStructuredType(condition.getStructuredType());
            resultJson = incomeplanFeign.structuredloan(dto, headers);
            log.info("structuredloan返回收入计划报文：" + resultJson);
        }
        // 灵活贴息还款
        else if (CalculateType.flexiblediscount.getValue().equals(algorithmType)) {
            dto.setRate(condition.getSettleRate());
            dto.setDiscount(condition.getDiscountAmt());
            resultJson = incomeplanFeign.flexiblediscount(dto, headers);
            log.info("flexiblediscount返回收入计划报文：" + resultJson);
        }
        // 等额累进还款
        else if (CalculateType.equalquota.getValue().equals(algorithmType)) {
            Integer step = condition.getLoanTerm()/condition.getStep();
            Assert.isTrue(condition.getLoanTerm()%condition.getStep()==0,"请输入正确的期数，必须是"+condition.getStep()+"的倍数");
            dto.setStep(step);
            dto.setStepPercent(condition.getStepPercent());
            resultJson = incomeplanFeign.equalquota(dto, headers);
            log.info("equalquota返回收入计划报文：" + resultJson);
        }
        // 任意贷还款
        else if (CalculateType.arbitraryloan.getValue().equals(algorithmType)) {
            // 合并租金和期数
            this.mergedRentAndPeroid(condition, condition.getRentList());
            dto.setPeroids(condition.getPeroids());
            dto.setMoney(condition.getMoney());
            resultJson = incomeplanFeign.arbitraryloan(dto, headers);
            log.info("arbitraryloan返回收入计划报文：" + resultJson);
        }
        // 等比累进还款
        else if (CalculateType.equalratioret.getValue().equals(algorithmType)) {
            Integer step = condition.getLoanTerm()/condition.getStep();
            Assert.isTrue(condition.getLoanTerm()%condition.getStep()==0,"请输入正确的期数，必须是"+condition.getStep()+"的倍数");
            dto.setStep(step);
            dto.setStepPercent(condition.getStepPercent());
            resultJson = incomeplanFeign.equalratioret(dto, headers);
            log.info("equalratioret返回收入计划报文：" + resultJson);
        }
        Assert.isTrue(1 == resultJson.getInteger("success"), resultJson.getString("message"));
        return resultJson;
    }

    /**
     * 计算IRR
     *
     * @param list
     * @return
     */
    public BigDecimal calIRR(String list) {
        //请求头
        Map headers = makeHeader();
        //接口返回结果
        JSONObject result = toolsFeign.irr(list, headers);
        //返回报错
        Assert.isTrue(1 == result.getInteger("success"), result.getString("message"));
        return new BigDecimal(result.get("data").toString());
    }

}
